home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / pointers.swg / 0032_Link List Handling.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-09-04  |  8.3 KB  |  391 lines

  1.  
  2. { TEST PROGRAM AT END !! }
  3.  
  4. { Links Unit - Turbo Pascal 5.5
  5.   Patterned after the list processing facility in Simula class SIMSET.
  6.   Simula fans will note the same naming conventions as Simula-67.
  7.  
  8.   Written by Bill Zech @CIS:[73547,1034]), May 16, 1989.
  9.  
  10.   The Links unit defines objects and methods useful for implementing
  11.   list (set) membership in your own objects.
  12.  
  13.   Any object which inherits object <Link> will acquire the attributes
  14.   needed to maintain that object in a doubly-linked list.  Because the
  15.   Linkage object only has one set of forward and backward pointers, a
  16.   given object may belong to only one list at any given moment.  This
  17.   is sufficient for many purposes.  For example, a task control block
  18.   might belong in either a ready list, a suspended list, or a swapped
  19.   list, but all are mutually exclusive.
  20.  
  21.   A list is defined as a head node and zero or more objects linked
  22.   to the head node.  A head node with no other members is an empty
  23.   list.  Procedures and functions are provided to add members to the
  24.   end of the list, insert new members in position relative to an
  25.   existing member, determine the first member, last member, size
  26.   (cardinality) of the list, and to remove members from the list.
  27.  
  28.   Because your object inherits all these attributes, your program
  29.   need not concern itself with allocating or maintaining pointers
  30.   or other stuff.  All the actual linkage mechanisms will be
  31.   transparent to your object.
  32.  
  33.   *Note*
  34.       The following discussion assumes you have defined your objects
  35.       as static variables instead of pointers to objects.  For most
  36.       programs, dynamic objects manipulated with pointers will be
  37.       more useful.  Some methods require pointers as arguments.
  38.       Example program TLIST.PAS uses pointer type variables.
  39.  
  40.   Define your object as required, inheriting object Link:
  41.  
  42.         type
  43.             myObjType = object(Link)
  44.                 xxx.....xxxx
  45.             end;
  46.  
  47.   To establish a new list, declare a variable for the head node
  48.   as a type Head:
  49.  
  50.         var
  51.             Queue1    :Head;
  52.             Queue2    :Head;
  53.  
  54.     Define your object variables:
  55.  
  56.         var
  57.             X    : myObjType;
  58.             Y    : myObjType;
  59.             Z    : myObjType;
  60.             P    :^myObjType;
  61.  
  62.     Make sure the objects have been Init'ed as required for data
  63.     initialization, VMT setup, etc.
  64.  
  65.             Queue1.Init;
  66.             Queue2.Init;
  67.             X.Init;
  68.             Y.Init;
  69.             Z.Init;
  70.  
  71.     You can add your objects to a list with <Into>:
  72.     (Note the use of the @ operator to make QueueX a pointer to the
  73.      object.)
  74.  
  75.         begin
  76.             X.Into(@Queue1);
  77.             Y.Into(@Queue2);
  78.  
  79.     You can insert at a specific place with <Precede> or <Follow>:
  80.  
  81.             Z.Precede(@Y);
  82.             Z.Follow(@Y);
  83.  
  84.     Remove an object with <Out>:
  85.  
  86.             Y.Out;
  87.  
  88.     Then add it to another list:
  89.  
  90.             Y.Into(@Queue1);
  91.  
  92.     Note that <Into>, <Precede> and <Follow> all have a built-in
  93.     call to Out, so to move an object from one list to another can
  94.     be had with a single operation:
  95.  
  96.             Z.Into(@Queue1);
  97.  
  98.     You can determine the first and last elements with <First> and <Last>:
  99.     (Note the functions return pointers to objects.)
  100.  
  101.             P := Queue1.First;
  102.             P := Queue1.Last;
  103.  
  104.     The succcessor or predecessor of a given member can be found with
  105.     fucntions <Suc> and <Pred>:
  106.  
  107.             P := X.Pred;
  108.             P := Y.Suc;
  109.             P := P^.Suc;
  110.  
  111.     The number of elements in a list is found with <Cardinal>:
  112.  
  113.             N := Queue1.Cardinal;
  114.  
  115.     <Empty> returns TRUE is the list has no members:
  116.  
  117.             if Queue1.Empty then ...
  118.  
  119.     You can remove all members from a list with <Clear>:
  120.  
  121.             Queue1.Clear;
  122.  
  123.     GENERAL NOTES:
  124.  
  125.         The TP 5.5 type compatibility rules allow a pointer to a
  126.         descendant be assigned to an ancestor pointer, but not vice-versa.
  127.         So although it is perfectly legal to assign a pointer to
  128.         type myObjType to a pointer to type Linkage, it won't let
  129.         us do it the opposite.
  130.  
  131.         We would like to be able to assign returned values from
  132.         Suc, Pred, First, and Last to pointers of type myObjType,
  133.         and the least fussy way is to define these pointer types
  134.         internal to this unit as untyped pointers.  This works fine
  135.         because all we are really doing is passing around pointers
  136.         to Self, anyway.  The only down-side to this I have noticed
  137.         is you can't do:  P^.Suc^.Pred because the returned pointer
  138.         type cannot be dereferenced without a type cast.
  139. }
  140.  
  141. unit Links;
  142.  
  143. interface
  144.  
  145. type
  146.  
  147.   pLinkage = ^Linkage;
  148.   pLink = ^Link;
  149.   pHead = ^Head;
  150.  
  151.   Linkage = object
  152.       prede :pLinkage;
  153.       succ  :pLinkage;
  154.       function Suc  :pointer;
  155.       function Pred :pointer;
  156.       constructor Init;
  157.   end;
  158.  
  159.   Link = object(Linkage)
  160.       procedure Out;
  161.       procedure Into(s :pHead);
  162.       procedure Follow (x :pLinkage);
  163.       procedure Precede(x :pLinkage);
  164.   end;
  165.  
  166.   Head = object(Linkage)
  167.       function First :pointer;
  168.       function Last  :pointer;
  169.       function Empty :boolean;
  170.       function Cardinal :integer;
  171.       procedure Clear;
  172.       constructor Init;
  173.   end;
  174.  
  175.  
  176.  
  177. implementation
  178.  
  179. constructor Linkage.Init;
  180. begin
  181.   succ := NIL;
  182.   prede := NIL;
  183. end;
  184.  
  185. function Linkage.Suc :pointer;
  186. begin
  187.   if TypeOf(succ^) = TypeOf(Head) then
  188.      Suc := NIL
  189.   else Suc := succ;
  190. end;
  191.  
  192. function Linkage.Pred :pointer;
  193. begin
  194.   if TypeOf(prede^) = TypeOf(Head) then
  195.      Pred := NIL
  196.   else Pred := prede;
  197. end;
  198.  
  199. procedure Link.Out;
  200. begin
  201.     if succ <> NIL then
  202.     begin
  203.       succ^.prede := prede;
  204.       prede^.succ := succ;
  205.       succ := NIL;
  206.       prede := NIL;
  207.     end;
  208. end;
  209.  
  210. procedure Link.Follow(x :pLinkage);
  211. begin
  212.     Out;
  213.     if x <> NIL then
  214.     begin
  215.       if x^.succ <> NIL then
  216.       begin
  217.           prede := x;
  218.           succ := x^.succ;
  219.           x^.succ := @Self;
  220.           succ^.prede := @Self;
  221.       end;
  222.     end;
  223. end;
  224.  
  225.  
  226. procedure Link.Precede(x :pLinkage);
  227. begin
  228.     Out;
  229.     if x <> NIL then
  230.     begin
  231.         if x^.succ <> NIL then
  232.         begin
  233.             succ := x;
  234.             prede := x^.prede;
  235.             x^.prede := @Self;
  236.             prede^.succ := @Self;
  237.         end;
  238.     end;
  239. end;
  240.  
  241. procedure Link.Into(s :pHead);
  242. begin
  243.     Out;
  244.     if s <> NIL then
  245.     begin
  246.         succ := s;
  247.         prede := s^.prede;
  248.         s^.prede := @Self;
  249.         prede^.succ := @Self;
  250.     end;
  251. end;
  252.  
  253.  
  254. function Head.First :pointer;
  255. begin
  256.     First := suc;
  257. end;
  258.  
  259. function Head.Last :pointer;
  260. begin
  261.     Last := Pred;
  262. end;
  263.  
  264. function Head.Empty :boolean;
  265. begin
  266.   Empty := succ = prede;
  267. end;
  268.  
  269. function Head.Cardinal :integer;
  270. var
  271.     i   :integer;
  272.     p   :pLinkage;
  273. begin
  274.     i := 0;
  275.     p := succ;
  276.     while p <> @Self do
  277.       begin
  278.           i := i + 1;
  279.           p := p^.succ;
  280.       end;
  281.     Cardinal := i;
  282. end;
  283.  
  284. procedure Head.Clear;
  285. var
  286.     x  : pLink;
  287. begin
  288.     x := First;
  289.     while x <> NIL do
  290.       begin
  291.           x^.Out;
  292.           x := First;
  293.       end;
  294. end;
  295.  
  296. constructor Head.Init;
  297. begin
  298.   succ := @Self;
  299.   prede := @Self;
  300. end;
  301.  
  302. end.
  303.  
  304.  
  305. { -----------------------   TEST PROGRAM ----------- }
  306.  
  307. program tlist;
  308.  
  309. uses Links;
  310.  
  311. type
  312.     NameType = string[10];
  313.     person = object(link)
  314.         name :NameType;
  315.         constructor init(nameArg :NameType);
  316.     end;
  317.     Pperson = ^person;
  318.  
  319. constructor person.init(nameArg :NameType);
  320. begin
  321.     name := nameArg;
  322.     link.init;
  323. end;
  324.  
  325. var
  326.     queue : Phead;
  327.     man   : Pperson;
  328.     man2  : Pperson;
  329.     n     : integer;
  330.     tf    : boolean;
  331.  
  332. begin
  333.     new(queue,Init);
  334.     tf := queue^.Empty;
  335.     new(man,Init('Bill'));
  336.     man^.Into(queue);
  337.     new(man,Init('Tom'));
  338.     man^.Into(queue);
  339.     new(man,Init('Jerry'));
  340.     man^.Into(queue);
  341.  
  342.     man := queue^.First;
  343.     writeln('First man in queue is ',man^.name);
  344.     man := queue^.Last;
  345.     writeln('Last man in queue is ',man^.name);
  346.  
  347.     n := queue^.Cardinal;
  348.     writeln('Length of queue is ',n);
  349.     if not queue^.Empty then writeln('EMPTY reports queue NOT empty');
  350.  
  351.     new(man2,Init('Hugo'));
  352.     man2^.Precede(man);
  353.  
  354.     new(man2,Init('Alfonso'));
  355.     man2^.Follow(man);
  356.     { should now be: Bill Tom Hugo Jerry Alfonso }
  357.     writeln('After PRECEDE and FOLLOW calls, list should be:');
  358.     writeln('  {Bill, Tom, Hugo, Jerry, Alfonso}');
  359.     writeln('Actual list is:');
  360.  
  361.     man := queue^.First;
  362.     while man <> NIL do
  363.       begin
  364.           write(man^.name,' ');
  365.           man := man^.Suc;
  366.       end;
  367.       writeln;
  368.  
  369.     man := queue^.Last;
  370.     writeln('The same list backwards is:');
  371.     while man <> NIL do
  372.       begin
  373.          write(man^.name,' ');
  374.          man := man^.Pred;
  375.       end;
  376.       writeln;
  377.  
  378.     n := queue^.Cardinal;
  379.     writeln('Queue size should be 5 now, is: ', n);
  380.  
  381.     queue^.Clear;
  382.     writeln('After clear operation,');
  383.     n := queue^.Cardinal;
  384.     writeln('   Queue size is ',n);
  385.     tf := queue^.Empty;
  386.     if tf then writeln('    and EMTPY reports queue is empty.');
  387.     writeln;
  388.     writeln('Done with test.');
  389. end.
  390.  
  391.